/******************************************************************************

	COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2009, 2010.

	This file is part of Maxsi Engine.

	Maxsi Engine is free software: you can redistribute it and/or modify it
	under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or (at your
	option) any later version.

	Maxsi engine is distributed in the hope that it will be useful, but WITHOUT
	ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
	FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
	for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with Maxsi Engine. If not, see <http://www.gnu.org/licenses/>.

	MaxsiEngine.dll
	A general purpose C++ library for the Maxsi Technology Project.

	MaxsiWin32.cpp
	Basic Win32 Functionallity.

******************************************************************************/

#include "MaxsiEngine.h"

#if 0
#include "winsock2.h"

BeginMaxsiNamespace

/****************************************************************************
	FUNCTIONS
****************************************************************************/


ME_Win32Entry*		Entry				=	0;
bool				IgnoreMEAssertions	=	false;

bool	SetWin32EntryPointClass	(ME_Win32Entry* NewEntry)
{
	Entry	=	NewEntry;
	return true;
}

#ifdef __MINGW_H // MinGW Hack/Workaround
void* ME_GetExceptionFilter()
{
	return NULL;
}
#endif

bool	IssueMEAssertionFailure(MESTR* Message)
{
	if ( IgnoreMEAssertions ) { return false; }
	LRESULT		Result		=	ME_SendThreadMessage(Entry->WindowHWND,ME_Assertion_Failure,(LPARAM)Message);
	return (Result != IDABORT);
}


DWORD	ME_Thread::OnMEAssertionFailure(char* Message)
{
	int	Result	=	MessageBoxA(
		WindowHWND,
		Message,
		"ME_Thread::OnMEAssertionFailure",
		MB_ICONWARNING | MB_ABORTRETRYIGNORE | MB_DEFBUTTON1 | MB_TASKMODAL | MB_SETFOREGROUND);

	if ( Result == IDABORT )
	{
		//PostQuitMessage(0);
	}
	else if ( Result == IDRETRY )
	{

	}
	else if ( Result == IDIGNORE )
	{
		IgnoreMEAssertions	=	true;
	}
	return (DWORD)(Result);
}

HANDLE	ME_CreateThread(LPTHREAD_START_ROUTINE lpStartAddress, HWND Parent)
{		
	ME_Thread_Parameters* Params	=	new	ME_Thread_Parameters;

	Params->Command					=	ME_Thread_Cmd_GetDefaultStackSpace;

	DWORD	DefaultStackSpace		=	lpStartAddress(Params);		

	Params							=	new	ME_Thread_Parameters;

	Params->Command					=	ME_Thread_Cmd_Create;
	Params->Parent					=	Parent;

	return CreateThread(NULL,DefaultStackSpace,lpStartAddress,Params,0,NULL);		
}


BOOL ME_PostThreadMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	return PostMessage(hWnd,ME_ThreadMessageID,wParam,lParam);
}

LRESULT ME_SendThreadMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	return SendMessage(hWnd,ME_ThreadMessageID,wParam,lParam);
}

UINT	g_ME_ThreadMessageIDFunc	=	0;

// Returns the ID of the windows message that ME_Thread uses
const UINT ME_ThreadMessageIDFunc(void)
{
	if ( g_ME_ThreadMessageIDFunc )
		return g_ME_ThreadMessageIDFunc;

	g_ME_ThreadMessageIDFunc	=	RegisterWindowMessageA("ME_ThreadMessageID");

	return		g_ME_ThreadMessageIDFunc;

	// TODO: Use the command to automatically get a msg that is uniq to ME_Thread
	//RegisterWindowMessage() http://msdn.microsoft.com/en-us/library/ms644947(VS.85).aspx

	// Maybe?
	//return RegisterWindowMessageA("ME_ThreadMessageID");

	//return	0xSORTIE00
	//return		0x50F71300;
	//return		g_ME_ThreadMessageIDFunc;
}


// Returns the ID of the windows message that ME_Thread uses
ME_Window* ME_WindowGetPointer(HWND Handle)
{
	return	(ME_Window*)ME_SendThreadMessage(Handle,ME_Thread_Cmd_GetME_WindowPointer,0);
}

/****************************************************************************
	ME_Window::
****************************************************************************/

ME_Window::ME_Window()
{
	WindowHWND		=		0;
	Form			=		0;
	SubWindows		=		0;
}

ME_Window::~ME_Window()
{
	DeleteList(SubWindows);
	// TODO: Delete stuff here!
}

BOOL ME_Window::TerminateApplication()
{
	Form		=		TerminateForm(Form);

	return TRUE;
}

BOOL ME_Window::InitApplication(HANDLE hInstance)
{
	// Should be handled in a child class
	return FALSE;
}

BOOL ME_Window::InitInstance(HINSTANCE hInstance, INT nCmdShow)
{
	// Should be handled in a child class
	return FALSE;
}	

LRESULT APIENTRY ME_Window::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	bool	Handled		=	true;
	LRESULT	Result		=	0;

	if ( message == ME_ThreadMessageID )
	{
		if (wParam == ME_Thread_Cmd_GetME_WindowPointer ){return (LRESULT)this;}
	}

	if ( g_Win7TBC == ULONG_MAX || g_Win7TBC == 0 )
	{
		g_Win7TBC	=	RegisterWindowMessageA("TaskbarButtonCreated");

		if ( g_Win7TBC == 0 )
		{
			ME_UNDEFINED_BEHAVIOR("Failed to register window message TaskbarButtonCreated!");
		}
	}

	if (message==g_Win7TBC)
	{
		EnableWin7TaskBar(hWnd);
	}
	
	switch (message) 
	{
		case WM_COMMAND:
			break;

		//case WM_SIZE:
		//	break;

		//case WM_PAINT:
		//	break;

		case WM_DESTROY:
			PostQuitMessage(0);
			Form	=	TerminateForm(Form);
			break;

		default:
			Handled		=	false;
			
			if (!Form)
			{
				// We don't have a form, simply handle this ourselves.
				Result = DefWindowProc(hWnd, message, wParam, lParam);
			}
	}

	if ( Form )
	{
		if ( Handled )
		{
			// Just forward, but don't return its result
						Form->WindowProc(hWnd,message,wParam,lParam);
		}
		else
		{	
			// We didn't handle it, forward and return the result;
			Result	=	Form->WindowProc(hWnd,message,wParam,lParam);
		}
	}

	return Result;
}


/****************************************************************************
	ME_Thread::
****************************************************************************/

ME_Thread::ME_Thread()
{
	hInst			=	GetModuleHandle(NULL);
	SubThreads		=	NULL;
}

ME_Thread::~ME_Thread()
{
	DeleteList(SubThreads);
	// TODO: Delete stuff here!
}	

DWORD ME_Thread::DefaultStackSpace( void )
{
	return (DWORD)NULL; // NULL means Windows' Default (Which happens to be = 1 MB)
}

DWORD WINAPI ME_Thread::EntryPoint(LPVOID parameter)
{
	ME_Thread_Parameters* Params = (ME_Thread_Parameters*)parameter;

	if ( Params->Command != ME_Thread_Cmd_Create )
	{
		return (DWORD)ME_Thread_Cmd(0,(WPARAM)Params->Command,(LPARAM)Params->Parameter);
	}

	Parent	=	Params->Parent;

	if (InitApplication(hInst) &&
		InitInstance(hInst, Params->nCmdShow))
	{
		if ( !WindowHWND) return 0;

		if ( Parent )
		{
			ME_SendThreadMessage(Parent,ME_Thread_Cmd_Register,(LPARAM)WindowHWND);
		}

		MSG		msg			=	{0};
		BOOL	bRet		=	FALSE;

		// Begin the mainloop
		while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
		{ 
			if (bRet == -1)
			{
				break;
			}
			else
			{
				/* Only translate message if it is not an accelerator message */
				if (!TranslateAccelerator((HWND)WindowHWND, hAccTable, &msg))
				{
					TranslateMessage(&msg);
					DispatchMessage(&msg); 
				}
			}
		}

		return (int) (msg.wParam);
	}
	return 0;
}

// Handles internal thread messages, make sure to forward unknown messages to the base class!

LRESULT APIENTRY ME_Thread::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	UINT	ME_ThreadMessageMSGID	=	ME_ThreadMessageID;
	if ( message == ME_ThreadMessageMSGID )
	{
		return ME_Thread_Cmd(hWnd, wParam,lParam);
	}
		
	// Forward unknown messages to the BaseClass
	return (BaseClass::WindowProc(hWnd, message, wParam, lParam));
}

LRESULT ME_Thread::ME_Thread_Cmd(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	switch (wParam)
	{
		// Handle Messages here
		case ME_Thread_Cmd_Null: {}	break;
		case ME_Thread_Cmd_Create: {}	break;
		case ME_Thread_Cmd_GetDefaultStackSpace: { return DefaultStackSpace(); }	break;
		case ME_Thread_Cmd_Register: { return OnThreadRegistered((HWND)lParam); }	break;
		case ME_Thread_Cmd_Initialize: { return OnThreadInitialize(lParam); }	break;
		case ME_Thread_Cmd_Terminate: { return OnThreadInitialize(lParam); }	break;
		case ME_Thread_Cmd_SetParent: { return OnNewParent((HWND)lParam); }	break;
		case ME_Assertion_Failure: { return OnMEAssertionFailure((char*)lParam); }	break;

		// Forward unknown messages to the BaseClass
		default:
			return (BaseClass::WindowProc(hWnd, ME_ThreadMessageID, wParam, lParam));
	}
	return (0);
}

DWORD ME_Thread::OnThreadRegistered(HWND hWnd)
{
	bool	Result	=	AddListEntry_s(&SubThreads,(BYTE*)&hWnd,sizeof(HWND));

	if ( Result )
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}
DWORD ME_Thread::OnNewParent(HWND hWnd)
{
	Parent = hWnd;
	return TRUE;
}
DWORD ME_Thread::OnThreadInitialize(LPARAM lParam)
{
	// Should be handled in a child class
	return TRUE;
}
DWORD ME_Thread::OnThreadTerminate(LPARAM lParam)
{		
	if (lParam & ME_Thread_Cmd_SelfTerminate || lParam == 0)
	{
		PostQuitMessage(0);
	}
	if (lParam & ME_Thread_Cmd_SelfTerminate || lParam == 0)
	{
		size_t	NumThreads		=	GetListSize(SubThreads);
		for (size_t N = 0; N < NumThreads; N++)
		{
			ME_PostThreadMessage((HWND)GetListEntry(SubThreads,N),ME_Thread_Cmd_Terminate,ME_Thread_Cmd_FullTermination);
		}
	}

	return TRUE;
}

/****************************************************************************
	ME_Win32Entry::
****************************************************************************/

int WINAPI ME_Win32Entry::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	// Initialize the Common Controls
	INITCOMMONCONTROLSEX Controls;

	Controls.dwICC		=	ICC_PROGRESS_CLASS | ICC_WIN95_CLASSES;
	Controls.dwSize		=	sizeof(Controls);

	InitCommonControlsEx(&Controls);

	hInst				=	hInstance;

	ME_Thread_Parameters Params;

	memset(&Params,0,sizeof(Params));

	Params.Command		=	ME_Thread_Cmd_Create;
	Params.nCmdShow		=	nCmdShow;

	return (int) BaseClass::EntryPoint((LPVOID)&Params);
}

BOOL ME_Win32Entry::InitApplication(HANDLE hInstance)
{
	return BaseClass::InitApplication(hInstance);
}

BOOL ME_Win32Entry::InitInstance(HINSTANCE hInstance, INT nCmdShow)
{
	return BaseClass::InitInstance(hInstance,nCmdShow);
}

LRESULT APIENTRY ME_Win32Entry::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	return BaseClass::WindowProc(hWnd,message,wParam,lParam);
}

EndMaxsiNamespace

#endif

